﻿using Opc.Ua;
using Opc.Ua.Client;
using SHRIS.MIS.Common.Util.Extension;
using SHRIS.MIS.Entity.ScadaBaseInfo;
using SHRIS.MIS.Entity.ScadaData;
using SHRIS.MIS.Service.OpcService;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SHRIS.MIS.Service.Device
{
    public class FineLathe_05 : BasicDevice
    {
        #region device parameters

        private Guid opcServiceId;

        private string materialCode;
        /// <summary>
        /// 物料码
        /// </summary>
        public string MaterialCode
        {
            get
            {
                return materialCode;
            }
            set
            {
                string previewVlaue = materialCode;
                materialCode = value;
                OnPropertyChanged("MaterialCode", previewVlaue, materialCode);
            }
        }


        private int _cncStatus;
        /// <summary>
        /// CNC 当前状态 1=interrupted 2=stopped 3=in progresss 4=waiting 5=aborted
        /// /Channel/State/progStatus[u1]
        /// </summary>
        public int CncStatus
        {
            get
            {
                return _cncStatus;
            }
            set
            {
                if (_cncStatus != value)
                {
                    int previewVlaue = _cncStatus;
                    _cncStatus = value;
                    OnPropertyChanged("CncStatus", previewVlaue, _cncStatus);
                }

            }
        }


        private int _cncOpMode = -1;
        /// <summary>
        /// CNC 当前工作模式 0=JOG 1=MDI 2=AUTO
        /// /Bag/State/opMode[u1]
        /// </summary>
        public int CncOpMode
        {
            get
            {
                return _cncOpMode;
            }
            set
            {
                if (_cncOpMode != value)
                {
                    int previewVlaue = _cncOpMode;
                    _cncOpMode = value;
                    OnPropertyChanged("CncOpMode", previewVlaue, _cncOpMode);
                }

            }
        }

        private string _programName;
        /// <summary>
        /// CNC 当前主程序名称
        /// /Channel/ProgramInfo/progName[u1]
        /// </summary>
        public string ProgramName
        {
            get
            {
                return _programName;
            }
            set
            {
                if (_programName != value)
                {
                    string previewVlaue = _programName;
                    _programName = value;
                    OnPropertyChanged("ProgramName", previewVlaue, _programName);
                }

            }
        }

        private int _ncuBootTime;
        /// <summary>
        /// NCU 的开机总运行时间  单位：分钟
        /// /Nck/ChannelDiagnose/setupTime[u1]
        /// </summary>
        public int NcuBootTime
        {
            get
            {
                return _ncuBootTime;
            }
            set
            {
                if (_ncuBootTime != value)
                {
                    int previewVlaue = _ncuBootTime;
                    _ncuBootTime = value;
                    OnPropertyChanged("NcuBootTime", previewVlaue, _ncuBootTime);
                }

            }
        }

        private double _ncuOperationTime;
        /// <summary>
        /// NCU 程序加工累计时间
        /// /Channel/ChannelDiagnose/operatingTime[u1,1]
        /// </summary>
        public double NcuOperationTime
        {
            get
            {
                return _ncuOperationTime;
            }
            set
            {
                if (_ncuOperationTime != value)
                {
                    double previewVlaue = _ncuOperationTime;
                    _ncuOperationTime = value;
                    OnPropertyChanged("NcuOperationTime", previewVlaue, _ncuOperationTime);
                }

            }
        }

        private double _ncuCycleTime;
        /// <summary>
        /// NCU 当前程序加工时间
        /// /Channel/ChannelDiagnose/cycleTime[u1,1]
        /// </summary>
        public double NcuCycleTime
        {
            get
            {
                return _ncuCycleTime;
            }
            set
            {
                if (_ncuCycleTime != value)
                {
                    double previewVlaue = _ncuCycleTime;
                    _ncuCycleTime = value;
                    OnPropertyChanged("NcuCycleTime", previewVlaue, _ncuCycleTime);
                }

            }
        }

        private string _actToolName;
        /// <summary>
        /// 当前刀具名
        /// /Channel/State/actToolIdent[u1]
        /// </summary>
        public string ActToolName
        {
            get
            {
                return _actToolName;
            }
            set
            {
                if (_actToolName != value)
                {
                    string previewVlaue = _actToolName;
                    _actToolName = value;
                    OnPropertyChanged("ActToolName", previewVlaue, _actToolName);
                }

            }
        }

        private int _actDNumber;
        /// <summary>
        /// 当前刀沿
        ///  /Channel/State/actDNumber[u1]
        /// </summary>
        public int ActDNumber
        {
            get
            {
                return _actDNumber;
            }
            set
            {
                if (_actDNumber != value)
                {
                    int previewVlaue = _actDNumber;
                    _actDNumber = value;
                    OnPropertyChanged("ActDNumber", previewVlaue, _actDNumber);
                }

            }
        }


        private double _actToolBasePosX;
        /// <summary>
        /// 当前轴坐标 X
        ///  /Channel/GeometricAxis/actToolBasePos[u1,1]
        /// </summary>
        public double ActToolBasePosX
        {
            get
            {
                return _actToolBasePosX;
            }
            set
            {
                if (_actToolBasePosX != value)
                {
                    double previewVlaue = _actToolBasePosX;
                    _actToolBasePosX = value;
                    OnPropertyChanged("ActToolBasePosX", previewVlaue, _actToolBasePosX);
                }

            }
        }

        private double _actToolBasePosZ;
        /// <summary>
        /// 当前轴坐标 Z
        /// /Channel/GeometricAxis/actToolBasePos[u1,2]
        /// </summary>
        public double ActToolBasePosZ
        {
            get
            {
                return _actToolBasePosZ;
            }
            set
            {
                if (_actToolBasePosZ != value)
                {
                    double previewVlaue = _actToolBasePosZ;
                    _actToolBasePosZ = value;
                    OnPropertyChanged("ActToolBasePosZ", previewVlaue, _actToolBasePosZ);
                }

            }
        }

        private double _spindleSetSpeed;
        /// <summary>
        /// 主轴设置速度
        ///  /Channel/Spindle/cmdSpeed[u1]
        /// </summary>
        public double SpindleSetSpeed
        {
            get
            {
                return _spindleSetSpeed;
            }
            set
            {
                if (_spindleSetSpeed != value)
                {
                    double previewVlaue = _spindleSetSpeed;
                    _spindleSetSpeed = value;
                    OnPropertyChanged("SpindleSetSpeed", previewVlaue, _spindleSetSpeed);
                }

            }
        }


        private double _spindleActSpeed;
        /// <summary>
        /// 主轴实际速度
        ///  /Channel/Spindle/actSpeed[u1]
        /// </summary>
        public double SpindleActSpeed
        {
            get
            {
                return _spindleActSpeed;
            }
            set
            {
                if (_spindleActSpeed != value)
                {
                    double previewVlaue = _spindleActSpeed;
                    _spindleActSpeed = value;
                    OnPropertyChanged("SpindleActSpeed", previewVlaue, _spindleActSpeed);
                }

            }
        }


        private double _spindleSetFeedRate;
        /// <summary>
        /// 切削指定速度
        ///  /Channel/GeometricAxis/cmdFeedRate[u1,1]
        /// </summary>
        public double SpindleSetFeedRate
        {
            get
            {
                return _spindleSetFeedRate;
            }
            set
            {
                if (_spindleSetFeedRate != value)
                {
                    double previewVlaue = _spindleSetFeedRate;
                    _spindleSetFeedRate = value;
                    OnPropertyChanged("SpindleSetFeedRate", previewVlaue, _spindleSetFeedRate);
                }

            }
        }

        private double _spindleActFeedRate;
        /// <summary>
        /// 切削实际速度
        ///  /Channel/GeometricAxis/actFeedRate[u1,1]
        /// </summary>
        public double SpindleActFeedRate
        {
            get
            {
                return _spindleActFeedRate;
            }
            set
            {
                if (_spindleActFeedRate != value)
                {
                    double previewVlaue = _spindleActFeedRate;
                    _spindleActFeedRate = value;
                    OnPropertyChanged("SpindleActFeedRate", previewVlaue, _spindleActFeedRate);
                }

            }
        }

        private double _spindleSpeedOverRate;
        /// <summary>
        /// 主轴倍率
        ///  /Channel/Spindle/speedOvr[u1,1]
        /// </summary>
        public double SpindleSpeedOverRate
        {
            get
            {
                return _spindleSpeedOverRate;
            }
            set
            {
                if (_spindleSpeedOverRate != value)
                {
                    double previewVlaue = _spindleSpeedOverRate;
                    _spindleSpeedOverRate = value;
                    OnPropertyChanged("SpindleSpeedOverRate", previewVlaue, _spindleSpeedOverRate);
                }

            }
        }

        private double _cutSpeedOverRate;
        /// <summary>
        /// 切削倍率
        ///  /Channel/GeometricAxis/feedRateOvr[u1,1]
        /// </summary>
        public double CutSpeedOverRate
        {
            get
            {
                return _cutSpeedOverRate;
            }
            set
            {
                if (_cutSpeedOverRate != value)
                {
                    double previewVlaue = _cutSpeedOverRate;
                    _cutSpeedOverRate = value;
                    OnPropertyChanged("CutSpeedOverRate", previewVlaue, _cutSpeedOverRate);
                }

            }
        }

        private double _spindleLoad;
        /// <summary>
        /// 主轴负载
        ///  /Channel/Spindle/driveLoad
        /// </summary>
        public double SpindleLoad
        {
            get
            {
                return _spindleLoad;
            }
            set
            {
                if (_spindleLoad != value)
                {
                    double previewVlaue = _spindleLoad;
                    _spindleLoad = value;
                    OnPropertyChanged("SpindleLoad", previewVlaue, _spindleLoad);
                }

            }
        }

        /// <summary>
        /// 机床报警列表1，对应PLC DB9041.DBD76
        /// </summary>
        private List<string> alarmList1 = new List<string>
        {
            "","700001/急停","700002/滤油器堵塞","700003/空调报警","700004/中心架润滑压力低","700005/液压电机过载","700006/排屑器过载","700007/液压压力低",
            "700008/机床未准备好","700009/主轴风机过载","","700011/刀架锁紧超时","","700013/刀塔不在正确刀位上","700014/编程刀号大于实际刀号","700015/防护门打开",
            "700016/润滑压力低","700017/高压冷却电机过载","","700019/润滑液位低","700020/卡盘内外检测同时亮","700021/卡盘未夹紧主轴启动","700022/卡盘未夹紧启动程序","700023/卡盘夹紧超过时间",
            "700024/卡盘未夹紧时间超","","","700027/换刀时间长","700028/+X限位","700029/-X限位","700030/+Z限位","700031/-Z限位"
        };

        /// <summary>
        /// 机床报警列表2，对应PLC DB9041.DBD80
        /// </summary>
        private List<string> alarmList2 = new List<string>
        {
            "","700033/手持盒生效","","","","","","",
            "","","","700043/吸雾器电机过载","700044/提升泵电机过载","700045/高压冷却系统报警","700046/冲屑电机过载","700047/主轴换挡失败",
            "700048/气密检测异常","700049/刀架故障，请查看刀架驱动报警","700050/刀架外部24V低","700051/刀架电机超速","700052/刀架松开后，锁紧信号不消失","700053/刀架松开后锁紧信号出现","700054/刀架锁紧状态，锁紧信号丢失","700055/刀架锁紧超时",
            "700056/刀架电机过载","700057/操纵箱不在安全位置","700058/主轴高低档位异常检测档位，请勿旋转主轴","700059/机床与机械手通讯异常","","","",""
        };

        private FineLathe05ProcessData _fineLathe05ProcessData = new FineLathe05ProcessData();

        public FineLathe05ProcessData FineLathe05ProcessData
        {
            get
            {
                return _fineLathe05ProcessData;
            }
            set
            {
                _fineLathe05ProcessData = value;
                OnPropertyChanged("FineLathe05ProcessData", _fineLathe05ProcessData, _fineLathe05ProcessData);
            }
        }



        /// <summary>
        /// 控制是否反馈生产过程参数的token
        /// </summary>
        private CancellationTokenSource processDataCancelToken;

        #endregion

        #region device config

        //状态
        //cnc 状态 /Channel/State/progStatus[u1]   Uint 1=interrupted 2=stopped 3=in progresss 4=waiting 5=aborted
        //cnc 工作模式 /Bag/State/opMode[u1]   0=JOG 1=MDI 2=AUTO
        // 急停  from PLC


        //程序控制
        // cnc 主程序 /Channel/ProgramInfo/progName[u1]   似乎每个轴都有一个主程序
        // 累计开机时间  /Nck/ChannelDiagnose/setupTime[u1] 
        //程序加工时间 


        //过程数据
        //主轴实际速度 /Channel/Spindle/actSpeed[u1]
        //主轴设置速度 /Channel/Spindle/cmdSpeed[u1]
        //主轴负载  /Channel/Spindle/driveLoad








        #endregion

        private readonly IEnumerable<OpcDataSourceEntity> _opcDataSourceEntities;
        public FineLathe_05(DeviceEntity deviceEntity,
            WorkshopCommunicationService workshopCommunicationService,
            IEnumerable<OpcDataSourceEntity> opcDataSourceEntities)
            : base(deviceEntity, workshopCommunicationService)
        {
            _opcDataSourceEntities = opcDataSourceEntities;
            CheckOutDataType();
        }

        private void CheckOutDataType()
        {
            //对所有OPC 数据类型进行校验，如果不对记入LOG

        }



        public override void InitalDevice()
        {
            //创建opc 订阅  就分成一个通道，数据收集由LineManager完成
            

            //状态通道  程序号；状态  模式
            var subscriptionStatus= _opcDataSourceEntities.Where(i => i.DataAction == 4);
            //找出订阅数据的服务器列表
            var serverIds = subscriptionStatus.Select(i => i.ServerId).Distinct();

            if (serverIds.Count() == 1)
            {
                opcServiceId = serverIds.First();
                _workshopCommunicationService.CreateOpcSubscription(subscriptionStatus, DataHandlerStatus);
            }

        }

        private void DataHandlerStatus(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
        {
            try
            {
                MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
                //Console.WriteLine(notification.Value.StatusCode.ToString());

                if (notification != null)
                {
                    Guid dataId = new Guid();
                    bool isId = Guid.TryParse(monitoredItem.DisplayName, out dataId);
                    if (isId && (!dataId.IsGuidNullOrEmpty()))
                    {
                        var dataSource = _opcDataSourceEntities.Where(i => i.Id == dataId).First();
                        switch (dataSource.DataName)
                        {
                            case "CncStatus":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        CncStatus =int.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        CncStatus = -1;
                                    }
                                    if (CncStatus == 3)
                                    {
                                        if (processDataCancelToken != null)
                                        {
                                            processDataCancelToken.Cancel();
                                            processDataCancelToken.Dispose();
                                        }
                                        processDataCancelToken = new CancellationTokenSource();
                                        Task.Run(() => ProcessDataFeedBack(1000, processDataCancelToken.Token), processDataCancelToken.Token);
                                    }
                                    else
                                    {
                                        if (processDataCancelToken != null)
                                        {
                                            processDataCancelToken.Cancel();
                                            processDataCancelToken.Dispose();
                                        }
                                    }
                                    break;
                                }

                            case "CncOpMode":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        CncOpMode =int.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        CncOpMode = -1;
                                    }                                    
                                    break;
                                }
                            case "ProgramName":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        ProgramName = notification.Value.Value.ToString();
                                    }
                                    else
                                    {
                                        ProgramName = "未知";
                                    }                                    
                                    break;
                                }

                            case "NcuBootTime":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        NcuBootTime =int.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        NcuBootTime = -1;
                                    }                                    
                                    break;
                                }

                            case "NcuOperationTime":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        NcuOperationTime = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        NcuOperationTime = -1;
                                    }
                                    break;
                                }

                            case "NcuCycleTime":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        NcuCycleTime = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        NcuCycleTime = 0;
                                    }
                                    break;
                                }

                            case "ActToolName":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        ActToolName = notification.Value.Value.ToString();
                                    }
                                    else
                                    {
                                        ActToolName = "未知";
                                    }
                                    break;
                                }

                            case "ActDNumber":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        ActDNumber = int.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        ActDNumber = -1;
                                    }
                                    break;
                                }

                            case "ActToolBasePosX":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        ActToolBasePosX = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        ActToolBasePosX = 0;
                                    }
                                    break;
                                }

                            case "ActToolBasePosZ":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        ActToolBasePosZ = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        ActToolBasePosZ = 0;
                                    }
                                    break;
                                }

                            case "SpindleSetSpeed":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        SpindleSetSpeed = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        SpindleSetSpeed = 0;
                                    }
                                    break;
                                }

                            case "SpindleActSpeed":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        SpindleActSpeed = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        SpindleActSpeed = 0;
                                    }
                                    break;
                                }

                            case "SpindleSetFeedRate":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        SpindleSetFeedRate = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        SpindleSetFeedRate = 0;
                                    }
                                    break;
                                }

                            case "SpindleActFeedRate":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        SpindleActFeedRate = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        SpindleActFeedRate = 0;
                                    }
                                    break;
                                }

                            case "SpindleSpeedOverRate":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        SpindleSpeedOverRate = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        SpindleSpeedOverRate = 0;
                                    }
                                    break;
                                }

                            case "CutSpeedOverRate":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        CutSpeedOverRate = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        CutSpeedOverRate = 0;
                                    }
                                    break;
                                }

                            case "SpindleLoad":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        SpindleLoad = double.Parse(notification.Value.Value.ToString());
                                    }
                                    else
                                    {
                                        SpindleLoad = 0;
                                    }
                                    break;
                                }
                            case "MaterialCode":
                                {
                                    if (notification.Value.Value != null)
                                    {
                                        MaterialCode = notification.Value.Value.ToString();
                                    }
                                    break;
                                }

                            default:
                                {
                                    break;
                                }
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }




        public async Task ProcessDataFeedBack(int millionSecond, CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                FineLathe05ProcessData fineLathe05ProcessData = new FineLathe05ProcessData();
                fineLathe05ProcessData.ActToolName = ActToolName;
                fineLathe05ProcessData.SpindleSetSpeed = _spindleSetSpeed;
                fineLathe05ProcessData.SpindleActSpeed = _spindleActSpeed;
                fineLathe05ProcessData.SpindleSetFeedRate = _spindleSetFeedRate;
                fineLathe05ProcessData.SpindleActFeedRate = _spindleActFeedRate;
                fineLathe05ProcessData.SpindleLoad = _spindleLoad;
                fineLathe05ProcessData.ProgramName = _programName;
                FineLathe05ProcessData = fineLathe05ProcessData;
                await Task.Delay(millionSecond);
            }
        }


        #region 获取机床报警

        public List<DeviceAlarm> GetDeviceAlarms()
        {
            List<string> tags = new List<string>();
            // DB9041.DBD76
            string alarmAddress1 = "ns=2;s=Xibei01.MainPlcControl.MainPlcControl.Alarm.Alarm1";
            // DB9041.DBD80
            string alarmAddress2 = "ns=2;s=Xibei01.MainPlcControl.MainPlcControl.Alarm.Alarm2";
            tags.Add(alarmAddress1);
            tags.Add(alarmAddress2);
            int result1 = 0;
            int result2 = 0;
            try
            {
                List<DataValue> dataValues = _workshopCommunicationService.ReadValues(opcServiceId, tags);
                if (dataValues != null)
                {
                    if (dataValues[0] != null)
                    {
                        result1 = int.Parse(dataValues[0].Value.ToString());
                    }
                    if (dataValues[1] != null)
                    {
                        result2 = int.Parse(dataValues[1].Value.ToString());
                    }
                }
                List<DeviceAlarm> list1=analysisAlarmResult(result1,alarmList1);
                List<DeviceAlarm> list2=analysisAlarmResult(result2,alarmList2);
                return list1.Concat(list2).ToList<DeviceAlarm>();
            }
            catch(Exception ex)
            {

            }
            
            return null;
        }

        public List<DeviceAlarm> analysisAlarmResult(int result,List<string> alarmList)
        {

            int alarmIndex = 0;
            List<DeviceAlarm> list = new List<DeviceAlarm>();

            byte[] bResult = intToBytes(result);
            for(int i = 0; i < bResult.Length; i++)
            {
                BitArray bitArray = new BitArray(bResult[i]);
                for(int j = 0; j < bitArray.Length; j++)
                {
                    if (bitArray[j])
                    {
                        string[] alarmInfo= alarmList[alarmIndex].Split("/");
                        DeviceAlarm deviceAlarm = new DeviceAlarm();
                        deviceAlarm.alarmID = alarmInfo[0];
                        deviceAlarm.alarmInfo = alarmInfo[1];
                        list.Add(deviceAlarm);
                    }
                    alarmIndex++;
                }
            }
            return list;
        }

        /// <summary>
        /// 将int值转为byte数组，用于机床报警，转为byte数组使用
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public byte[] intToBytes(int value)
        {
            byte[] src = new byte[4];
            src[3] = (byte)((value >> 24) & 0xFF);
            src[2] = (byte)((value >> 16) & 0xFF);
            src[1] = (byte)((value >> 8) & 0xFF);
            src[0] = (byte)(value & 0xFF);
            return src;
        }
        #endregion

        #region 刀具管理方法
        public ToolHouseDescription GetToolHouseInfo()
        {
            //默认只有一个刀库
            //string toolHouseNumberAddress = "/Tool/MagazineCatalogue/numActMags[u1]";
            //DataValue toolHouseNumber = _workshopCommunicationService.ReadValue(opcServiceId, toolHouseNumberAddress);

            ToolHouseDescription toolHouseDescription = new ToolHouseDescription();

            //刀库号
            string toolHouseIndexAddress = "ns=2;s=/Tool/MagazineCatalogue/magVNo[u1,1]";
            //刀库名称
            string toolHouseNameAddress= "ns=2;s=/Tool/MagazineCatalogue/magVIdent[u1,1]";

            List<string> tags = new List<string>();
            tags.Add(toolHouseIndexAddress);
            tags.Add(toolHouseNameAddress);
            try
            {
                List<DataValue> dataValues = _workshopCommunicationService.ReadValues(opcServiceId, tags);
                if (dataValues != null)
                {
                    if (dataValues[0].Value != null)
                    {
                        toolHouseDescription.ToolHouseIndex = int.Parse(dataValues[0].Value.ToString());
                    }
                    else
                    {
                        toolHouseDescription.ToolHouseIndex = 0;
                    }

                    if (dataValues[1].Value != null)
                    {
                        toolHouseDescription.ToolHouseName = dataValues[1].Value.ToString();
                    }
                    else
                    {
                        toolHouseDescription.ToolHouseName = "";
                    }
                }              
            }
            catch(Exception ex)
            {
                return null;
            }
            //刀库的刀位信息
            string toolHousePlaceAddress = string.Format("ns=2;s=/Tool/MagazineDescription/magNrPlaces[u1,{0}]", toolHouseDescription.ToolHouseIndex);
            try
            {
                DataValue toolHousePlaces = _workshopCommunicationService.ReadValue(opcServiceId, toolHousePlaceAddress);
                if (toolHousePlaces != null)
                {
                    if (toolHousePlaces.Value != null)
                    {
                        toolHouseDescription.ToolPlaceCount = int.Parse(toolHousePlaces.Value.ToString());
                    }
                    else
                    {
                        toolHouseDescription.ToolPlaceCount = 0;
                    }
                }                
                return toolHouseDescription;
            }
            catch(Exception ex)
            {
                return null;
            }

        }

        /// <summary>
        /// 获取刀具信息列表
        /// </summary>
        /// <returns></returns>
        public List<ToolListInfo> GetToolInfo()
        {
            //默认只有一个刀库
            //  /Tool / Catalogue / numTools[u1]  刀具表中刀具数量

            //刀具表中刀具数量
            string toolCountAddress = "ns=2;s=/Tool/Catalogue/numTools[u1]";
            try
            {
                DataValue toolCounts = _workshopCommunicationService.ReadValue(opcServiceId, toolCountAddress);
                int counts = 0;
                if (toolCounts != null)
                {
                    if (toolCounts.Value != null)
                    {
                        counts = int.Parse(toolCounts.Value.ToString());
                    }
                }
                List<string> tags = new List<string>();
                for(int i=0;i<counts;i++)
                {
                    string toolNameAddress = string.Format("ns=2;s=/Tool/Catalogue/toolIdent[u1,{0}]",i);
                    string toolIndexAddress = string.Format("ns=2;s=/Tool/Catalogue/toolNo[u1,{0}]", i);
                    string toolHouseAddress = string.Format("ns=2;s=/Tool/Catalogue/toolInMag[u1,{0}]", i);
                    string toolPlaceAddress = string.Format("ns=2;s=/Tool/Catalogue/toolInPlace[u1,{0}]", i);
                    tags.Add(toolNameAddress);
                    tags.Add(toolIndexAddress);
                    tags.Add(toolHouseAddress);
                    tags.Add(toolPlaceAddress);
                }
                List<DataValue> dataValues = _workshopCommunicationService.ReadValues(opcServiceId, tags);
                List<ToolListInfo> toolListInfos = new List<ToolListInfo>();
                for(int i=0;i<counts;i++)
                {
                    ToolListInfo toolListInfo = new ToolListInfo();
                    if(dataValues[i * 4 + 0].Value != null)
                    {
                        toolListInfo.ToolName = dataValues[i * 4 + 0].Value.ToString();
                    }
                    else
                    {
                        toolListInfo.ToolName = "";
                    }
                    if(dataValues[i * 4 + 1].Value != null)
                    {
                        toolListInfo.ToolIndex = int.Parse(dataValues[i * 4 + 1].Value.ToString());
                    }
                    else
                    {
                        toolListInfo.ToolIndex = 0;
                    }
                    if(dataValues[i * 4 + 2].Value != null)
                    {
                        toolListInfo.ToolHouseIndex = int.Parse(dataValues[i * 4 + 2].Value.ToString());
                    }
                    else
                    {
                        toolListInfo.ToolHouseIndex = 0;
                    }
                    if(dataValues[i * 4 + 3].Value != null)
                    {
                        toolListInfo.ToolPlace = int.Parse(dataValues[i * 4 + 3].Value.ToString());
                    }
                    else
                    {
                        toolListInfo.ToolPlace = 0;
                    }
                    
                    
                    toolListInfos.Add(toolListInfo);
                }
                return toolListInfos;
            }
            catch(Exception ex)
            {
                return null;
            }
        }

        /**
         * 获取刀补
         */
        public ToolEdgeInfo GetToolEdgeInfo(int toolIndex)
        {
            ToolEdgeInfo toolEdgeInfo = new ToolEdgeInfo();
            toolEdgeInfo.ToolIndex = toolIndex;
            List<string> tags = new List<string>();
            string toolTypeAddress = string.Format("ns=2;s=/Tool/Compensation/edgeData[u1,c{0},1]", toolIndex);
            string toolXAddress = string.Format("ns=2;s=/Tool/Compensation/edgeData[u1,c{0},3]", toolIndex);
            string toolZAddress = string.Format("ns=2;s=/Tool/Compensation/edgeData[u1,c{0},4]", toolIndex);
            string toolRAddress = string.Format("ns=2;s=/Tool/Compensation/edgeData[u1,c{0},6]", toolIndex);
            tags.Add(toolTypeAddress);
            tags.Add(toolXAddress);
            tags.Add(toolZAddress);
            tags.Add(toolRAddress);
            List<DataValue> dataValues = _workshopCommunicationService.ReadValues(opcServiceId, tags);
            if (dataValues != null && dataValues.Count >= 4)
            {
                if (dataValues[0].Value != null)
                {
                    toolEdgeInfo.ToolType = dataValues[0].Value.ToString();
                }
                else
                {
                    toolEdgeInfo.ToolType = "0";
                }

                if (dataValues[1].Value != null)
                {
                    toolEdgeInfo.ToolGeometryX = dataValues[1].Value.ToString();
                }
                else
                {
                    toolEdgeInfo.ToolGeometryX = "Unknow";
                }

                if (dataValues[2].Value != null)
                {
                    toolEdgeInfo.ToolGeometryZ = dataValues[2].Value.ToString();
                }
                else
                {
                    toolEdgeInfo.ToolGeometryZ = "Unknow";
                }

                if (dataValues[3].Value != null)
                {
                    toolEdgeInfo.ToolGeometryR = dataValues[3].Value.ToString();
                }
                else
                {
                    toolEdgeInfo.ToolGeometryR = "Unknow";
                }
            }
            return toolEdgeInfo;
        }

        /// <summary>
        /// 设置刀补
        /// </summary>
        /// <param name="toolIndex">刀具号</param>
        /// <param name="offX">X偏移，设置null代表不处理</param>
        /// <param name="offZ">Z偏移，设置null代表不处理</param>
        /// <param name="offR">R偏移，设置null代表不处理</param>
        public void setToolEdge(int toolIndex,double? offX,double? offZ,double? offR)
        {
            if (offX != null)
            {
                string toolXAddress = string.Format("ns=2;s=/Tool/Compensation/edgeData[u1,c{0},3]", toolIndex);
                _workshopCommunicationService.WriteValue(opcServiceId, toolXAddress, offX);
            }
            if (offZ != null)
            {
                string toolZAddress = string.Format("ns=2;s=/Tool/Compensation/edgeData[u1,c{0},4]", toolIndex);
                _workshopCommunicationService.WriteValue(opcServiceId, toolZAddress, offZ);
            }
            if (offR != null)
            {
                string toolRAddress = string.Format("ns=2;s=/Tool/Compensation/edgeData[u1,c{0},6]", toolIndex);
                _workshopCommunicationService.WriteValue(opcServiceId, toolRAddress, offR);
            }
        }
        #endregion     
    }

    #region 刀具自定义类
    public class FineLathe05ProcessData
    {
        /// <summary>
        /// 主轴设置速度
        /// </summary>
        public double SpindleSetSpeed { get; set; }

        /// <summary>
        /// 主轴实际速度
        /// </summary>
        public double SpindleActSpeed { get; set; }

        /// <summary>
        /// 切削设定速度
        /// </summary>
        public double SpindleSetFeedRate { get; set; }

        /// <summary>
        /// 切削实际速度
        /// </summary>
        public double SpindleActFeedRate { get; set; }

        /// <summary>
        /// 主轴负载
        /// </summary>
        public double SpindleLoad { get; set; }

        /// <summary>
        /// 当前刀具号
        /// </summary>
        public string ActToolName { get; set; }

        /// <summary>
        /// 当前程序名
        /// </summary>
        public string ProgramName { get; set; }


    }

    public class ToolHouseDescription
    {
        /// <summary>
        /// 刀库号
        /// ns=2;s=/Tool/MagazineCatalogue/magVNo[u1,1]
        /// </summary>
        public int ToolHouseIndex { get; set; }

        /// <summary>
        /// 刀库名称
        ///  ns=2;s=/Tool/MagazineCatalogue/magVIdent[u1,1]
        /// </summary>
        public string ToolHouseName { get; set; }

        /// <summary>
        /// 刀库中刀位数量
        ///  ns=2;s=/Tool/MagazineDescription/magNrPlaces[u1,{0}]
        /// </summary>
        public int ToolPlaceCount { get; set; }

    }

    public class ToolListInfo
    {

        // /Tool/Catalogue/numTools[u1]  刀具表中刀具数量
        // /Tool/Catalogue/toolNo[u1,m] 刀具表中第m行的刀具的内部索引号
        // /Tool/Catalogue/toolIdent[u1,m] 刀具表中第m行的刀具名称
        // /Tool/Catalogue/toolInMag[u1,m]  该刀具存储的刀库号
        // /Tool/Catalogue/toolInPlace[u1,m]  该刀具存储的刀库中的刀位号


        /// <summary>
        /// 刀具名称
        /// </summary>
        public string ToolName { get; set; }

        /// <summary>
        /// 刀具的内部索引号
        /// </summary>
        public int ToolIndex { get; set; }

        /// <summary>
        /// 刀具所属的刀库的刀库号
        /// </summary>
        public int ToolHouseIndex { get; set; }


        /// <summary>
        /// 刀具在所属的刀库的刀位号
        /// </summary>
        public int ToolPlace { get; set; }
    }


    /// <summary>
    /// 刀刃信息
    /// </summary>
    public class ToolEdgeInfo
    {
        /// <summary>
        /// 刀具的内部索引号
        /// </summary>
        public int ToolIndex { get; set; }

        /// <summary>
        /// 刀具类型
        /// /Tool/Compensation/edgeData[u1,c1,1]
        /// </summary>
        public string ToolType { get; set; }

        /// <summary>
        /// 刀具长度 X
        /// /Tool/Compensation/edgeData[u1,c1,3]
        /// </summary>
        public string ToolGeometryX { get; set; }

        /// <summary>
        /// 刀具长度 Z
        ///  /Tool/Compensation/edgeData[u1,c1,4]
        /// </summary>
        public string ToolGeometryZ { get; set; }

        /// <summary>
        /// 刀具半径
        /// /Tool/Compensation/edgeData[u1,c1,6]
        /// </summary>
        public string ToolGeometryR { get; set; }


    }

    #endregion

    #region 机床报警类

    public class DeviceAlarm
    {
        /// <summary>
        /// 报警编码
        /// </summary>
        public String alarmID { get; set; }

        /// <summary>
        /// 报警信息
        /// </summary>
        public String alarmInfo { get; set; }

        /// <summary>
        /// 发生时间
        /// </summary>
        public DateTimeOffset occurTime { get; set; }
    }


   
    #endregion
}
